package com.oliver.proxy.midjourney.application.service;

import com.oliver.proxy.midjourney.domain.entity.TaskList;
import com.oliver.proxy.midjourney.domain.entity.InsertPoint;
import com.oliver.proxy.midjourney.domain.repository.TaskListRepository;
import com.oliver.proxy.midjourney.domain.exception.TaskValidationException;
import com.oliver.proxy.midjourney.interfaces.dto.CreateTaskRequest;
import com.oliver.proxy.midjourney.infrastructure.mapper.InsertPointMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Service
public class TaskListService {
    private final TaskListRepository taskListRepository;
    private final InsertPointMapper insertPointMapper;

    public TaskListService(TaskListRepository taskListRepository, InsertPointMapper insertPointMapper) {
        this.taskListRepository = taskListRepository;
        this.insertPointMapper = insertPointMapper;
    }

    @Transactional
    public Long createTask(CreateTaskRequest request) {
        validateTaskRequest(request);
        
        TaskList taskList = new TaskList();
        taskList.setTaskType(request.getTaskType());
        taskList.setTaskCategory(request.getTaskCategory());
        taskList.setTaskGenQty(request.getTaskGenQty());
        taskList.setTaskPrompt(request.getTaskPrompt());
        taskList.setAttritube1(request.getTemplate());
        taskList.setAttritube2(request.getDevName());
        taskList.setTaskStatus(0); // Default status
        
        // Set additional attributes
        taskList.setImgSize(request.getImgSize());

        // Handle taskSwitchNum based on taskType
        if (request.getTaskType() == 0) {
            taskList.setTaskSwitchNum(null);
            validateAndCreateInsertPoints(request, taskList);
        } else if (request.getTaskType() == 1) {
            taskList.setTaskSwitchNum(request.getTaskSwitchNum());
        }

        Long taskId = taskListRepository.save(taskList);
        taskList.setTaskId(taskId);

        // Save insert points if type is 0
        if (request.getTaskType() == 0 && request.getInsertPoints() != null && !request.getInsertPoints().isEmpty()) {
            List<InsertPoint> insertPoints = createInsertPoints(taskList.getTaskId(), request);
            insertPointMapper.batchInsert(insertPoints);
        }

        return taskId;
    }

    private void validateTaskRequest(CreateTaskRequest request) {
        // Validate taskType values
        if (request.getTaskType() != 0 && request.getTaskType() != 1) {
            throw new TaskValidationException("taskType must be either 0 or 1");
        }

        // Validate taskSwitchNum for taskType = 1
        if (request.getTaskType() == 1 && request.getTaskSwitchNum() == null) {
            throw new TaskValidationException("taskSwitchNum is required when taskType is 1");
        }
        
        // Validate imgSize for taskType = 1
        if (request.getTaskType() == 1 && !StringUtils.hasText(request.getImgSize())) {
            throw new TaskValidationException("imgSize is required when taskType is 1");
        }
    }

    private void validateAndCreateInsertPoints(CreateTaskRequest request, TaskList taskList) {
        if (request.getTaskType() != 0) {
            return;
        }

        // Count placeholders in prompt
        Pattern pattern = Pattern.compile("\\{(\\d+)\\}");
        Matcher matcher = pattern.matcher(request.getTaskPrompt());
        List<Integer> placeholders = new ArrayList<>();
        while (matcher.find()) {
            placeholders.add(Integer.parseInt(matcher.group(1)));
        }

        // Validate insert points
        if (request.getInsertPoints() == null || request.getInsertPoints().isEmpty()) {
            if (!placeholders.isEmpty()) {
                throw new TaskValidationException("Insert points are required for prompt with placeholders");
            }
            return;
        }

        placeholders = placeholders.stream()
                .distinct()
                .toList();
        // Check if number of insert points matches placeholders
        if (placeholders.size() != request.getInsertPoints().size()) {
            throw new TaskValidationException(
                String.format("Number of placeholders (%d) does not match number of insert points (%d)", 
                    placeholders.size(), request.getInsertPoints().size())
            );
        }

        // Validate that all required insert points are present
        for (int i = 0; i < placeholders.size(); i++) {
            String key = "insert" + (i + 1);
            if (!request.getInsertPoints().containsKey(key)) {
                throw new TaskValidationException("Missing insert point: " + key);
            }
        }
    }

    private List<InsertPoint> createInsertPoints(Long taskId, CreateTaskRequest request) {
        List<InsertPoint> insertPoints = new ArrayList<>();
        request.getInsertPoints().forEach((key, content) -> {
            int index = Integer.parseInt(key.substring(6)) - 1; // Extract number from "insert1", "insert2", etc.
            InsertPoint insertPoint = new InsertPoint();
            insertPoint.setTaskId(taskId);
            insertPoint.setPoint("{" + index + "}");
            insertPoint.setContent(content);
            insertPoints.add(insertPoint);
        });
        return insertPoints;
    }

    @Transactional
    public void updateTask(TaskList taskList) {
        taskListRepository.update(taskList);
    }

    @Transactional
    public void deleteTask(Long taskId) {
        taskListRepository.delete(taskId);
    }

    public TaskList getTask(Long taskId) {
        return taskListRepository.findById(taskId);
    }

    public List<TaskList> getAllTasks() {
        return taskListRepository.findAll();
    }

    public List<TaskList> getTasksByCategory(String category) {
        return taskListRepository.findByCategory(category);
    }
} 